﻿#region using statements

using System;
using System.Collections.Generic;
using System.Collections.Specialized;

#endregion

namespace NGen.Collections
{
	public class ObservableHashSet<TItemType> : HashSet<TItemType>, INotifyCollectionChanged
	{
		private readonly HashSet<TItemType> m_tempSet = new HashSet<TItemType>();

		#region INotifyCollectionChanged Members

		public event NotifyCollectionChangedEventHandler CollectionChanged;

		#endregion

		public new bool Add(TItemType p_item) {
			if(!base.Add(p_item)) {
				return false;
			}

			if(CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, p_item));
			}

			return true;
		}

		/// <summary>
		/// 	test
		/// </summary>
		/// <param name = "p_item"></param>
		/// <returns></returns>
		public new bool Remove(TItemType p_item) {
			if(!base.Remove(p_item)) {
				return false;
			}

			if(CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, p_item));
			}

			return true;
		}

		public new int RemoveWhere(Predicate<TItemType> p_match) {
			m_tempSet.Clear();
			m_tempSet.UnionWith(this);

			var result = base.RemoveWhere(p_match);

			m_tempSet.ExceptWith(this);

			if(result != 0 &&
			   CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, m_tempSet));
			}

			m_tempSet.Clear();
			return result;
		}

		public new void Clear() {
			base.Clear();
			if(CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			}
		}

		public new void ExceptWith(IEnumerable<TItemType> p_other) {
			m_tempSet.Clear();
			m_tempSet.UnionWith(this);

			base.ExceptWith(p_other);

			m_tempSet.UnionWith(p_other);

			if(m_tempSet.Count != Count &&
			   CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, m_tempSet));
			}

			m_tempSet.Clear();
		}

		public new void SymmetricExceptWith(IEnumerable<TItemType> p_other) {
			m_tempSet.Clear();
			m_tempSet.UnionWith(this);

			var preCount = Count;
			base.SymmetricExceptWith(p_other);

			if(preCount != Count &&
			   CollectionChanged != null) {
				m_tempSet.IntersectWith(p_other);
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, m_tempSet));
			}
			m_tempSet.Clear();
		}

		public new void UnionWith(IEnumerable<TItemType> p_other) {
			m_tempSet.Clear();
			m_tempSet.UnionWith(this);

			base.UnionWith(p_other);

			if(m_tempSet.Count != Count &&
			   CollectionChanged != null) {
				m_tempSet.ExceptWith(p_other);
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, m_tempSet));
			}

			m_tempSet.Clear();
		}

		public new void IntersectWith(IEnumerable<TItemType> p_other) {
			m_tempSet.Clear();
			m_tempSet.UnionWith(this);

			base.IntersectWith(p_other);

			if(m_tempSet.Count != Count &&
			   CollectionChanged != null) {
				m_tempSet.ExceptWith(p_other);
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, m_tempSet));
			}
		}

		private void _Notify(NotifyCollectionChangedAction p_action) {
			if(CollectionChanged != null) {
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(p_action));
			}
		}
	}
}